package cc.leap.service;

import cc.leap.constant.UserConstants;
import cc.leap.exception.ServiceException;
import cc.leap.mapper.SysRoleMapper;
import cc.leap.mapper.SysRoleMenuMapper;
import cc.leap.mapper.SysUserRoleMapper;
import cc.leap.model.PageQuery;
import cc.leap.model.TableDataInfo;
import cc.leap.model.domain.SysRole;
import cc.leap.model.domain.SysRoleMenu;
import cc.leap.model.domain.SysUser;
import cc.leap.model.domain.SysUserRole;
import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.data.annotation.Tran;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static cc.leap.model.domain.table.SysDeptTableDef.SYS_DEPT;
import static cc.leap.model.domain.table.SysRoleTableDef.SYS_ROLE;
import static cc.leap.model.domain.table.SysUserRoleTableDef.SYS_USER_ROLE;
import static cc.leap.model.domain.table.SysUserTableDef.SYS_USER;

/**
 * SysRoleService
 *
 * @author leap
 * @date 2024/8/19
 */
@Component
public class SysRoleService extends ServiceImpl<SysRoleMapper, SysRole> {

    @Inject
    SysRoleMapper roleMapper;

    @Inject
    SysUserRoleMapper userRoleMapper;

    @Inject
    SysRoleMenuMapper roleMenuMapper;

    private QueryWrapper buildQueryWrapper(SysRole roleBo) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(QueryMethods.distinct(SYS_ROLE.ALL_COLUMNS))
                .from(SYS_ROLE.as("r"))
                .leftJoin(SYS_USER_ROLE).as("ur").on(SYS_USER_ROLE.ROLE_ID.eq(SYS_ROLE.ROLE_ID))
                .leftJoin(SYS_USER).as("u").on(SYS_USER.USER_ID.eq(SYS_USER_ROLE.USER_ID))
                .leftJoin(SYS_DEPT).as("d").on(SYS_DEPT.DEPT_ID.eq(SYS_USER.DEPT_ID))
                .where(SYS_ROLE.DEL_FLAG.eq(0))
                .and(SYS_ROLE.ROLE_ID.eq(roleBo.getRoleId()))
                .and(SYS_ROLE.ROLE_NAME.like(roleBo.getRoleName()))
                .and(SYS_ROLE.STATUS.eq(roleBo.getStatus()))
                .and(SYS_ROLE.ROLE_KEY.like(roleBo.getRoleKey()))
                .and(SYS_ROLE.CREATE_TIME.between(roleBo.getParams().get("beginTime"), roleBo.getParams().get("endTime")))
                .orderBy(SYS_ROLE.ROLE_SORT.asc());
        return queryWrapper;
    }

    public List<SysRole> selectRoleAll() {
        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.select(SYS_ROLE.ROLE_ID, SYS_ROLE.ROLE_NAME, SYS_ROLE.ROLE_KEY, SYS_ROLE.ROLE_SORT, SYS_ROLE.STATUS)
                .from(SYS_ROLE);
        return this.list(queryWrapper);
    }

    public List<Long> selectRoleListByUserId(Long userId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
            .select(SYS_ROLE.ROLE_ID)
            .from(SYS_ROLE.as("r"))
            .leftJoin(SYS_USER_ROLE).as("ur").on(SYS_USER_ROLE.ROLE_ID.eq(SYS_ROLE.ROLE_ID))
            .leftJoin(SYS_USER).as("u").on(SYS_USER.USER_ID.eq(SYS_USER_ROLE.USER_ID))
            .where(SYS_USER.USER_ID.eq(userId));
        return this.listAs(queryWrapper, Long.class);
    }

    public TableDataInfo<SysRole> selectRolePage(SysRole role) {
        QueryWrapper queryWrapper = buildQueryWrapper(role);
        Page<SysRole> page = this.pageAs(PageQuery.build(), queryWrapper, SysRole.class);
        return TableDataInfo.build(page);
    }

    public List<SysRole> selectRolesByUserId(Long userId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(QueryMethods.distinct(SYS_ROLE.ALL_COLUMNS))
                .from(SYS_ROLE.as("r"))
                .leftJoin(SYS_USER_ROLE).as("ur").on(SYS_USER_ROLE.ROLE_ID.eq(SYS_ROLE.ROLE_ID))
                .leftJoin(SYS_USER).as("u").on(SYS_USER.USER_ID.eq(SYS_USER_ROLE.USER_ID))
                .leftJoin(SYS_DEPT).as("d").on(SYS_DEPT.DEPT_ID.eq(SYS_USER.DEPT_ID))
                .where(SYS_USER_ROLE.USER_ID.eq(userId));

        List<SysRole> userRoles = this.listAs(queryWrapper, SysRole.class);
        List<SysRole> roles = selectRoleAll();
        for (SysRole role : roles) {
            for (SysRole userRole : userRoles) {
                if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
                    role.setFlag(true);
                    break;
                }
            }
        }
        return roles;
    }

    public SysRole selectRoleById(Long roleId) {
        return this.getOneAs(query().select(SYS_ROLE.ROLE_ID, SYS_ROLE.ROLE_NAME, SYS_ROLE.ROLE_KEY, SYS_ROLE.ROLE_SORT, SYS_ROLE.STATUS)
                .where(SYS_ROLE.ROLE_ID.eq(roleId)), SysRole.class);
    }

    @Tran
    public int deleteRoleByIds(Long[] roleIds) {
        for (Long roleId : roleIds) {
            SysRole role = selectRoleById(roleId);
            if (countUserRoleByRoleId(roleId) > 0) {
                throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName()));
            }
        }
        // 删除角色与菜单关联
        roleMenuMapper.deleteRoleMenu(roleIds);

        return roleMapper.deleteRoleByIds(roleIds);
    }

    private int countUserRoleByRoleId(Long roleId) {
        return userRoleMapper.countUserRoleByRoleId(roleId);
    }

    public boolean checkRoleNameUnique(SysRole role) {
        Long roleId = ObjectUtil.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName());
        if (ObjectUtil.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    public boolean checkRoleKeyUnique(SysRole role) {
        Long roleId = ObjectUtil.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey());
        if (ObjectUtil.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    @Tran
    public int insertRole(SysRole role) {
        // 新增角色信息
        roleMapper.insertRole(role);
        return insertRoleMenu(role);
    }

    @Tran
    public int updateRole(SysRole role) {
        // 修改角色信息
        roleMapper.updateRole(role);
        // 删除角色与菜单关联
        roleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId());
        return insertRoleMenu(role);
    }

    /**
     * 新增角色菜单信息
     *
     * @param role 角色对象
     */
    public int insertRoleMenu(SysRole role) {
        int rows = 1;
        // 新增用户与角色管理
        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
        for (Long menuId : role.getMenuIds()) {
            SysRoleMenu rm = new SysRoleMenu();
            rm.setRoleId(role.getRoleId());
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (list.size() > 0) {
            rows = roleMenuMapper.batchRoleMenu(list);
        }
        return rows;
    }

    public int deleteAuthUser(SysUserRole userRole) {
        return userRoleMapper.deleteUserRoleInfo(userRole);
    }

}
